package blobDetector;

import java.util.Vector;

public class BlobDetectorGrid {
	
	BlobCell[][] grid;
	int w, h;
	Vector<Blob> blobs;
	float minIso=0;
	float maxIso=200;

	public BlobDetectorGrid(int w, int h) {
		this.w = w;
		this.h = h;
		grid = new BlobCell[w][h];// construction of array

		// filling the cells inside our grid
		for (int x = 0; x < grid.length; x++) {
			for (int y = 0; y < grid[x].length; y++) {
				BlobCell myCell = new BlobCell(x,y); // construction of cell
				

				grid[x][y] = myCell;//
			}
		}

		// assign the neighbours
		for (int x = 0; x < grid.length; x++) {
			for (int y = 0; y < grid[x].length; y++) {
				BlobCell cell = grid[x][y];
				BlobCell[] nbs = new BlobCell[8];
				nbs[0] = getCell(x + 1, y);
				nbs[1] = getCell(x + 1, y + 1);
				nbs[2] = getCell(x, y + 1);
				nbs[3] = getCell(x - 1, y + 1);
				nbs[4] = getCell(x - 1, y);
				nbs[5] = getCell(x - 1, y - 1);
				nbs[6] = getCell(x, y - 1);
				nbs[7] = getCell(x + 1, y - 1);
				cell.setNbs(nbs);
			}
		}
		
		blobs=new Vector<Blob>();
	}

	public void setValues(float[][] values) {
		for (int x = 0; x < values.length; x++) {
			float[] valueCol = values[x];
			BlobCell[] cellCol = grid[x];
			for (int y = 0; y < valueCol.length; y++) {
				BlobCell cell = cellCol[y];
				cell.setValue(valueCol[y]);
			}
		}
	}
	public void setValues(int[][] values) {
		for (int x = 0; x < values.length; x++) {
			int[] valueCol = values[x];
			BlobCell[] cellCol = grid[x];
			for (int y = 0; y < valueCol.length; y++) {
				BlobCell cell = cellCol[y];
				cell.setValue(valueCol[y]);
			}
		}
	}

	public void setValues(float[] values) {
		for (int x = 0; x < grid.length; x++) {
			BlobCell[] cellCol = grid[x];
			
			for (int y = 0; y < cellCol.length; y++) {
				int index = x+w*y;
				BlobCell cell = cellCol[y];
				cell.setValue(values[index]);
			}
		}
	}
	public void setValues(int[] values) {
		for (int x = 0; x < grid.length; x++) {
			BlobCell[] cellCol = grid[x];
			for (int y = 0; y < cellCol.length; y++) {
				int index = x+w*y;
				BlobCell cell = cellCol[y];
				cell.setValue(values[index]);
			}
		}
	}
	public boolean checkIfInside(BlobCell cell) {
		if (cell.getValue() > maxIso||cell.getValue()<minIso) {
			return false;
		} else {
			return true;
		}
	}

	public boolean checkIfBorder(BlobCell cell) {
		if (checkIfInside(cell) == false)
			return false;// too bright
		else {
			BlobCell[] nbs = cell.getNbs();
			for (int i = 0; i < nbs.length; i += 2) {
				BlobCell nb = nbs[i];
				if (nb == null || !checkIfInside(nb)) {// bright nb
					return true;
				}
			}
		}
		return false;
	}
	public int inverseDirection(int i) {
		return (i + 4) % 8;
	}
	public int getNextDirection(int lastDir, BlobCell cell) {
		BlobCell[] nbs = cell.getNbs();
		int cDir = lastDir + 1;
		cDir = cDir % 8;
		BlobCell cCell = nbs[cDir];
		int counter = 0;
		while (counter < 8 && (cCell == null || !checkIfBorder(cCell))) {
			cDir++;
			cDir = cDir % 8;
			cCell = nbs[cDir];
			counter++;
			// println(cDir);
		}
		if (counter >= 8)
			return -1;
		return cDir;
	}

	public BlobCell getCell(int x, int y) {
		if (x < 0 || x >= grid.length)
			return null;
		if (y < 0 || y >= grid[x].length)
			return null;
		return grid[x][y];
	}

	public void calculateBlobs(float maxIso) {
		calculateBlobs(0,maxIso);
	}
	
	public void calculateBlobs(float minIso,float maxIso) {
		this.minIso=minIso;
		this.maxIso=maxIso;
		 blobs = new Vector<Blob>();
		// all Cells should be unchecked;
		for (int x = 0; x < grid.length; x++) {
			for (int y = 0; y < grid[x].length; y++) {
				BlobCell cell = grid[x][y];
				cell.setChecked(false);
			}
		}

		for (int x = 0; x < grid.length; x++) {
			for (int y = 0; y < grid[x].length; y++) {
				BlobCell cell = grid[x][y];

				if (checkIfBorder(cell) && !cell.isChecked()) {
					
					int startDir = -1;
					BlobCell[] nbs = cell.getNbs();

					// finding starting direction
					for (int i = 0; i < nbs.length; i++) {
						BlobCell nb = nbs[i];
						if (nb == null || checkIfInside(nb) == false) {
							startDir = i;
							break;
						}
					}

					// looping around the blob
					BlobCell nextCell = cell;
					int nextDir = inverseDirection(startDir);
					
					Blob blob = new Blob();
					int minX=w+1;
					int minY=h+1;
					int maxX=-1;
					int maxY=-1;
					Vector<BlobCell> borders = new Vector<BlobCell>();

					do {
						int inverseDir = inverseDirection(nextDir);
						nextDir = getNextDirection(inverseDir, nextCell);
						if (nextDir == -1) {
							// single Pixel
						} else {
							nextCell = nextCell.getNbs()[nextDir];
						}
						
						if (nextCell.getX()>maxX)maxX=nextCell.x;
						if (nextCell.getY()>maxY)maxY=nextCell.y;
						if (nextCell.getX()<minX)minX=nextCell.x;
						if (nextCell.getY()<minY)minY=nextCell.y;
						if (!nextCell.isChecked()){
							nextCell.setChecked(true);
						borders.add(nextCell);
						}
					} while (nextCell != cell);
					//borders.r
					blob.setBorders(borders);
					blob.setMinX(minX);
					blob.setMaxX(maxX);
					blob.setMinY(minY);
					blob.setMaxY(maxY);
					if (borders.size()>1){
					blobs.add(blob);
					}
				}
			}
		}
		
	}

	public Vector<Blob> getBlobs() {
		return blobs;
	}
}
